﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Thor.Models
{
    public class BookingRequest : INotifyPropertyChanged, INotifyPropertyChanging, IDataErrorInfo
    {
        #region Fields
        private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

        private Dictionary<string, string> _errors = new Dictionary<string, string>();
        private DateTime _startTime;
        private DateTime _endTime;
        private Guid _calendarId;
        private string _calendarName;
        private string _calendarEmail;
        private string _subject;

        #endregion

        #region Constructors

        public BookingRequest() { }

        public BookingRequest(CalendarEntry entry)
        {
            CalendarId = entry.CalendarId;
            CalendarName = entry.CalendarName;
            CalendarEmail = entry.CalendarEmail;
            StartTime = entry.Time;
            EndTime = entry.Time.AddMinutes(30);
            Subject = "Impromptu Meeting";
            StartTimes = GetStartTimes(StartTime);
            EndTimes = GetEndTimes(EndTime);
        }

        #endregion

        #region Properties

        public Guid CalendarId 
        {
            get { return _calendarId; }
            set
            {
                if (_calendarId != value)
                {
                    OnCalendarIdChanging(value);
                    SendPropertyChanging();
                    _calendarId = value;
                    SendPropertyChanged("CalendarId");
                }
            }
        }
        
        public string CalendarName 
        {
            get { return _calendarName; }
            set
            {
                if (_calendarName != value)
                {
                    OnCalendarNameChanging(value);
                    SendPropertyChanging();
                    _calendarName = value;
                    SendPropertyChanged("CalendarName");
                }
            }
        }
        
        public string CalendarEmail 
        {
            get { return _calendarEmail; }
            set
            {
                if (_calendarEmail != value)
                {
                    OnCalendarEmailChanging(value);
                    SendPropertyChanging();
                    _calendarEmail = value;
                    SendPropertyChanged("CalendarEmail");
                }
            }
        }
        
        public DateTime StartTime
        {
            get { return _startTime; }
            set
            {
                if (_startTime != value)
                {
                    OnStartTimeChanging(value);
                    SendPropertyChanging();
                    _startTime = value;
                    StartTimes = GetStartTimes(_startTime);
                    SendPropertyChanged("StartTime");
                }
            }
        }

        public DateTime EndTime
        {
            get { return _endTime; }
            set
            {
                if (_endTime != value)
                {
                    OnEndTimeChanging(value);
                    SendPropertyChanging();
                    _endTime = value;
                    EndTimes = GetEndTimes(_endTime);
                    SendPropertyChanged("EndTime");
                }
            }
        }
        
        public string Subject 
        {
            get { return _subject; }
            set
            {
                if (_subject != value)
                {
                    OnSubjectChanging(value);
                    SendPropertyChanging();
                    _subject = value;
                    SendPropertyChanged("Subject");
                }
            }
        }

        public SelectList StartTimes { get; private set; }
        public SelectList EndTimes { get; private set; }

        #endregion

        #region Methods

        private SelectList GetStartTimes(DateTime selectedTime)
        {
            List<DateTimeListItem> list = new List<DateTimeListItem>();

            DateTime start = new DateTime(selectedTime.Year, selectedTime.Month, selectedTime.Day, 0, 0, 0);

            for (int i = 0; i <= 47; i++)
            {
                list.Add(new DateTimeListItem(start));
                start = start.AddMinutes(30);
            }

            return new SelectList(list, "Value", "Text", selectedTime);
        }

        private SelectList GetEndTimes(DateTime selectedTime)
        {
            List<DateTimeListItem> list = new List<DateTimeListItem>();

            DateTime start = new DateTime(selectedTime.Year, selectedTime.Month, selectedTime.Day, 0, 30, 0);

            for (int i = 0; i <= 47; i++)
            {
                list.Add(new DateTimeListItem(start));

                //We don't want to be able to book for the next day,
                //so we'll end at 11:59 PM instead of 12:00 AM
                if (i == 46)
                    start = start.AddMinutes(29);
                else
                    start = start.AddMinutes(30);
            }

            return new SelectList(list, "Value", "Text", selectedTime);
        }

        #endregion

        #region Property Changing Methods

        private void OnCalendarIdChanging(Guid value)
        {
            if (value == null || value == Guid.Empty)
                _errors.Add("CalendarId", "Calendar Id is required.");
        }

        private void OnCalendarNameChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("CalendarName", "Calendar Name is required.");
        }

        private void OnCalendarEmailChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("CalendarEmail", "Calendar Email is required.");
        }

        private void OnStartTimeChanging(DateTime value)
        {
            if (value == null)
            {
                _errors.Add("StartTime", "Start Time is required.");
            }
            else if (EndTime != null)
            {
                if (EndTime <= value)
                    _errors.Add("StarTime", "Start Time must be before the End Time.");
            }
        }

        private void OnEndTimeChanging(DateTime value)
        {
            if (value == null)
            {
                _errors.Add("Endtime", "End Time is required.");
            }
            else if (StartTime != null)
            {
                if (value <= StartTime)
                    _errors.Add("EndTime", "End Time must be after the Start Time.");
            }
        }

        private void OnSubjectChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Subject", "Subject is required.");
        }

        private void SendPropertyChanging()
        {
            if (PropertyChanging != null)
                PropertyChanging(this, emptyChangingEventArgs);
        }

        #endregion

        #region Property Changed Methods

        private void SendPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        #endregion

        #region IDataErrorInfo Members

        public string Error
        {
            get 
            { 
                return string.Empty; 
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                    return _errors[columnName];

                return string.Empty;
            }
        }

        #endregion
    }

    public class DateTimeListItem
    {
        public DateTimeListItem(DateTime dateTime)
        {
            this.DateTime = dateTime;
            this.Value = dateTime.ToString();
            this.Text = dateTime.ToShortTimeString().ToLower();
        }

        public DateTime DateTime { get; set; }
        public string Value { get; set; }
        public string Text { get; set; }
    }
}
